library(janitor)
library(readODS)
library(httr)
library(here)
library(data.table)
library(sf)
library(leaflet)
library(leaflet.extras)
library(tidyverse)
# loading in shape file 
uk_shape_file <- st_read(here("raw_data/LA_shape/Local_Authority_Districts__April_2019__UK_BFE_v2.shp")) %>%
  clean_names() %>% 
  st_simplify(dTolerance = 1000) %>%
  st_transform("+proj=longlat +datum=WGS84") %>% 
  dplyr::select(lad19cd, long, lat, geometry) 
# Set colours and bins
pal <- colorBin("Greens", domain = uk_ev_map$x2021_q1, bins = c(0, 500, 1000, 2500, 5000, 10000, 15000))

# Set labels
uk_ev_map_labels <- sprintf(
  "<strong>%s</strong><br/>%g Electric Vehicles",
  uk_ev_map$region_local_authority_apr_2019_3, uk_ev_map$x2021_q1) %>% 
  lapply(htmltools::HTML)
# Geospatial of EV Vehicles in the UK 2021 Q1
uk_ev_map %>% 
  leaflet() %>% 
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons(fillColor = ~pal(x2021_q1),
    weight = 0.1,
    opacity = 0.9, 
    color = "black",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(color = "green", weight = 2,
                                        bringToFront = TRUE),
    label = uk_ev_map_labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>% 
  addLegend(pal = pal, values = ~x2021_q1, opacity = 0.7, title = NULL,
            position = "bottomright")

How many electric vehicles are on the road across the UK by LA?

# Reading in and skipping first 5 rows
uk_ev_postcode <- read_ods(here("raw_data/ev_by_postcode.ods"), sheet = 2, skip = 6) %>% 
  rename("postcode" = PostcodeDistrict2)
Error: Can't rename columns that don't exist.
x Column `PostcodeDistrict2` doesn't exist.
Run `rlang::last_error()` to see where the error occurred.
# loading in shape file 
uk_shape_file_postcode <- st_read(here("raw_data/postcode_shape/EX_Sample.shp")) %>%
  clean_names() %>% 
  st_simplify(dTolerance = 1000) %>%
  st_transform("+proj=longlat +datum=WGS84") #%>% 
#  select(lad19cd, long, lat, geometry) 
# Joining uk_ev + shape file 
uk_ev_map_postcode <- uk_ev_postcode %>% 
  left_join(uk_shape_file_postcode, by = c("ons_la_code_apr_2019" = "lad19cd")) %>% 
  drop_na() %>% 
  mutate(across(c(x2021_q1:x2011_q4), as.numeric)) %>% 
  st_as_sf()
    pal <- colorBin("Greens", domain = uk_ev_map$x2021_q1, bins = c(0, 500, 1000, 2500, 5000, 10000, 15000))
    
    uk_ev_map_labels <- sprintf(
      "<strong>%s</strong><br/>%g Electric Vehicles",
      uk_ev_map$region_local_authority_apr_2019_3, uk_ev_map$x2021_q1) %>% 
      lapply(htmltools::HTML)
# Geospatial of EV Vehicles in the UK 2021 Q1
uk_ev_map %>% 
  leaflet() %>% 
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons(fillColor = ~pal(x2021_q1),
    weight = 0.1,
    opacity = 0.9, 
    color = "black",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(color = "green", weight = 2,
                                        bringToFront = TRUE),
    label = uk_ev_map_labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>% 
  addLegend(pal = pal, values = ~x2021_q1, opacity = 0.7, title = NULL,
            position = "bottomright")
# Wrangling to create an EV count over time plot 
uk_ev_longer <- uk_ev %>%
  # Pivot longer to get year and count columns
  pivot_longer(cols = c(x2021_q1:x2011_q4), names_to = c("year"), values_to = "no_of_ev") %>% 
  # Filter so we only have UK as a whole data AND we only want final numbers of the year so Q4 
  filter(region_local_authority_apr_2019_3 == "United Kingdom" & str_detect(year, "q4")) %>% 
  # Simplify to just show year
  mutate(year = case_when(str_detect(year, "2021") ~ "2021",
         str_detect(year, "2020") ~ "2020",
         str_detect(year, "2019") ~ "2019",
         str_detect(year, "2018") ~ "2018",
         str_detect(year, "2017") ~ "2017",
         str_detect(year, "2016") ~ "2016",
         str_detect(year, "2015") ~ "2015",
         str_detect(year, "2014") ~ "2014",
         str_detect(year, "2013") ~ "2013",
         str_detect(year, "2012") ~ "2012",
         str_detect(year, "2011") ~ "2011"),
         year = as.numeric(year),
         no_of_ev = as.numeric(no_of_ev))

Row binding grid NO2 data

no2_2010 <- read_csv(here("raw_data/no2_by_grid_2010.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2011 <- read_csv(here("raw_data/no2_by_grid_2011.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2012 <- read_csv(here("raw_data/no2_by_grid_2012.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2013 <- read_csv(here("raw_data/no2_by_grid_2013.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2014 <- read_csv(here("raw_data/no2_by_grid_2014.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2015 <- read_csv(here("raw_data/no2_by_grid_2015.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2016 <- read_csv(here("raw_data/no2_by_grid_2016.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2017 <- read_csv(here("raw_data/no2_by_grid_2017.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2018 <- read_csv(here("raw_data/no2_by_grid_2018.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
no2_2019 <- read_csv(here("raw_data/no2_by_grid_2019.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))

# Create empty data frame
no2_all <- data_frame()

# For each year, bind rows to one dataset
for (i in 2010:2019) {
  df_name <- paste0("no2_", i)
  df_input <- as.name(df_name)
  
  df <- eval(df_input) %>% 
    mutate(year = i)
  
no2_all <- bind_rows(no2_all, df)
  }
# Remove missing NO2 grid values
no2_clean <- no2_all %>% 
  filter(no2 != "MISSING")
library(proj4)
proj4string <- "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs"

no2_clean_row <- no2_clean %>% 
  rowid_to_column()

# Source data
xy <- no2_clean_row %>% 
  select(x, y, rowid)

# Transformed data
pj <- project(xy, proj4string, inverse=TRUE)
Warning in project(xy, proj4string, inverse = TRUE) :
  more than two dimensions found, using first two
latlon <- data.frame(xy, lat=pj$y, lon=pj$x)
final <-  merge(no2_clean_row, latlon, by.x = "rowid", by.y = "rowid") %>%
  filter(year == 2019) %>% 
  select(lat, lon, no2) 
final <- final %>% 
  mutate(no2 = as.numeric(no2)) 
bins <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
pal <- colorBin("Spectral", domain = final$no2, bins = bins, na.color = "transparent", reverse = TRUE)

leaflet() %>%
  addProviderTiles("CartoDB.Positron", options = providerTileOptions(noWrap = TRUE)) %>%
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addHeatmap(data = final,
             lng = ~lon,
             lat = ~lat,
             intensity = ~no2,
             minOpacity = 0.1,
             max = 45,
             radius = 1,
             blur = 1) %>% 
  addLegend(pal = pal, values = final$no2,
                title="Average NO2 Conc")
no2_annual_mean <- read_ods(here("raw_data/NO2_tables.ods"), sheet = 3, skip = 2) %>% 
  clean_names()
no2_annual_mean_all <- no2_annual_mean %>% 
  filter(site == "All sites") %>% 
  mutate(year = as.numeric(year))
no2_annual_mean_all %>% 
  ggplot() +
  aes(x = year, y = annual_mean_no2concentration_mg_m3) + 
  geom_point() +
  geom_smooth(se = FALSE) +
  theme_minimal() +
  scale_y_continuous(breaks = seq(0, 70, 10), limits = c(0, 70)) +
  theme(axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=1)) +
  labs(x = "\nYear\n", 
       y = "\nAnnual Mean NO2 Conc mg m3\n",
       title = "\nNO2 over time in the UK\n") 
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

library(tidyverse)
library(fable)
library(tsibble)
library(tsibbledata)
library(ggfortify)
forecast_no2 <- no2_annual_mean_all %>% 
  dplyr::select(year, annual_mean_no2concentration_mg_m3) %>% 
  tsibble(index = year)
autoplot(forecast_no2)
Plot variable not specified, automatically selected `.vars = annual_mean_no2concentration_mg_m3`

fit <- forecast_no2 %>%
  model(
    arima = ARIMA(annual_mean_no2concentration_mg_m3)
  )
fit
forecast_1 <- fit %>%
  fabletools::forecast(h = "15 years")
forecast_1
forecast_1 %>%
  autoplot(forecast_no2, level = NULL) +
  ggtitle("Forecasts for NO2 Conc over time") +
  xlab("Year") +
  guides(colour = guide_legend(title = "Forecast")) +
  scale_y_continuous(limit = c(0, 65))
Warning: Removed 1 row(s) containing missing values (geom_path).

# Now set our training data from 1992 to 2006
train <- forecast_no2 %>%
  filter(year <= 2017)

# run the model on the training set 
fit_train <- train %>%
  model(
    arima = ARIMA(annual_mean_no2concentration_mg_m3)
  )
# forecast from the training set
forecast_test <- fit_train %>% 
  fabletools::forecast(h = "4 years")

# Plot forecasts against actual values
forecast_test %>%
  autoplot(train, level = NULL) +
    autolayer(filter(forecast_no2, year >= 2017), color = "black") +
    ggtitle("Forecasts for NO2 Conc over time") +
    xlab("Year") + ylab("Megalitres") +
    guides(colour=guide_legend(title="Forecast"))
Plot variable not specified, automatically selected `.vars = annual_mean_no2concentration_mg_m3`

# Binding 2014 and 2019
no2_2014 <- read_csv(here("raw_data/no2_by_grid_2014.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2")) %>% 
  add_column(year = "2014")
Rows: 281802 Columns: 4
── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2019 <- read_csv(here("raw_data/no2_by_grid_2019.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2")) %>% 
  add_column(year = "2019")
Rows: 281802 Columns: 4
── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_difference <- bind_rows(no2_2014, no2_2019)
# Diff in NO2 between 2014 & 2019
no2_difference <- no2_difference %>% 
  filter(no2 != "MISSING") %>% 
  mutate(no2 = as.numeric(no2),
         year = as.numeric(year)) %>% 
  group_by(x, y) %>% 
  pivot_wider(names_from = "year", values_from = "no2") %>% 
  rename("x2014" = "2014",
         "x2019" = "2019") %>% 
  mutate(no2_diff_2014_2019 = x2014 - x2019)  %>% 
#Remove this separation when put in cleaning script
  ungroup() %>% 
#Remove this separation when put in cleaning script
  drop_na() %>% 
#Remove this separation when put in cleaning script
# Changing all negative numbers to zero as these aren't of interest to us
  mutate(no2_diff_2014_2019 = if_else(no2_diff_2014_2019 < 0, 0, no2_diff_2014_2019))
# Converting NO2 diff from x y to lat long
library(proj4)
proj4string <- "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs"

no2_diff_row <- no2_difference %>% 
  rowid_to_column()

# Source data
xy <- no2_diff_row %>% 
  dplyr::select(x, y, rowid)

# Transformed data
pj <- project(xy, proj4string, inverse=TRUE)
Warning in project(xy, proj4string, inverse = TRUE) :
  more than two dimensions found, using first two
latlon <- data.frame(xy, lat=pj$y, lon=pj$x)
no2_diff_final <-  merge(no2_diff_row, latlon, by.x = "rowid", by.y = "rowid") %>%
  dplyr::select(lat, lon, no2_diff_2014_2019) 
# Geospatial of No2 diff 2014 to 2019
bins <- c(0, 5, 10, 15, 20, 25, 30)
pal <- colorBin("Spectral", domain = no2_diff_final$no2_diff_2014_2019, bins = bins, na.color = "transparent", reverse = TRUE)

leaflet() %>%
  addProviderTiles("CartoDB.Positron", options = providerTileOptions(noWrap = TRUE)) %>%
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addHeatmap(data = no2_diff_final,
             lng = ~lon,
             lat = ~lat,
             intensity = ~no2_diff_2014_2019,
             minOpacity = 0.1,
             max = 30,
             radius = 1,
             blur = 2) %>% 
  addLegend(pal = pal, values = no2_diff_final$no2_diff_2014_2019,
                title="Annual Mean NO2 Change between 2014 and 2019")
no2_difference %>% 
  ggplot() +
  geom_histogram(aes(x = no2_diff_2014_2019))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ev_charging <- read_csv(here("raw_data/electric-vehicle-charging-device-statistics-july-2021/EVCD_02-Table 1.csv"), skip = 6) %>% 
  clean_names() %>% 
  dplyr::select(year, month, total_devices, rapid_devices) %>% 
  filter(rapid_devices != "NA") %>% 
  mutate(total_devices = as.numeric(total_devices),
         other_devices = total_devices - rapid_devices) %>% 
  select(-total_devices) %>% 
  pivot_longer(cols = c(other_devices, rapid_devices), names_to = "charger", values_to = "number_of_chargers") %>% 
  filter(month == "October" | month == "July" & year == "2021") %>% 
  mutate(charger = factor(charger, levels = c("rapid_devices", "other_devices")))

ev_charging_rapid <- read_csv(here("raw_data/electric-vehicle-charging-device-statistics-july-2021/EVCD_01b-Table 1.csv"), skip = 6) %>% 
  clean_names() %>% 
  select(la_region_code, local_authority_region_name, x6) %>% 
  rename("count_rapid" = x6)
ev_charging_total <- read_csv(here("raw_data/electric-vehicle-charging-device-statistics-july-2021/EVCD_01a-Table 1.csv"), skip = 6) %>% 
  clean_names() %>% 
  select(la_region_code, local_authority_region_name, x6) %>% 
  rename("count_total" = x6)

ev_charging_geo <- inner_join(ev_charging_rapid, ev_charging_total, by = "la_region_code") %>% 
  drop_na() %>% 
  select(la_region_code, local_authority_region_name.x, count_rapid, count_total) %>% 
  filter(str_detect(local_authority_region_name.x, "[a-z][a-z]"), 
         count_rapid != "-") %>% 
  mutate(local_authority_region_name.x = str_remove_all(local_authority_region_name.x, "[(](Met County)[)]"),
         local_authority_region_name.x = str_remove_all(local_authority_region_name.x, "[(]abolished \\w+ \\d+[)]"))
# Joining ev_charging_geo + shape file 
ev_charging_map <- ev_charging_geo %>% 
  inner_join(uk_shape_file, by = c("la_region_code" = "lad19cd")) %>% 
  mutate(across(c(count_rapid:count_total), as.numeric)) %>% 
  st_as_sf()
# Set colours and bins
pal <- colorBin("Reds", domain = ev_charging_map$count_total, bins = 10)

# Set labels
ev_charging_map_labels <- sprintf(
  "<strong>%s</strong><br/>%g Chargers",
  ev_charging_map$local_authority_region_name.x, ev_charging_map$count_total, ev_charging_map$count_rapid) %>% 
  lapply(htmltools::HTML)
# Geospatial of EV Total Chargers in the UK April 21
ev_charging_map %>% 
  leaflet() %>% 
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons(fillColor = ~pal(count_total),
    weight = 0.1,
    opacity = 0.9, 
    color = "black",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(color = "green", weight = 2,
                                        bringToFront = TRUE),
    label = ev_charging_map_labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>% 
  addLegend(pal = pal, values = ~count_total, opacity = 0.7, title = NULL,
            position = "bottomright")
# Set colours and bins
pal <- colorBin("Reds", domain = ev_charging_map$count_rapid, bins = 10)

# Set labels
ev_charging_map_labels <- sprintf(
  "<strong>%s</strong><br/>%g Chargers",
  ev_charging_map$local_authority_region_name.x, ev_charging_map$count_rapid, ev_charging_map$count_total) %>% 
  lapply(htmltools::HTML)
# Geospatial of EV Rapid Chargers per 100k people in the UK April 21
ev_charging_map %>% 
  leaflet() %>% 
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons(fillColor = ~pal(count_rapid),
    weight = 0.1,
    opacity = 0.9, 
    color = "black",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(color = "green", weight = 2,
                                        bringToFront = TRUE),
    label = ev_charging_map_labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>% 
  addLegend(pal = pal, values = ~count_rapid, opacity = 0.7, title = NULL,
            position = "bottomright")
# st_join seems less dirty
ev_no2 <- final %>% 
  st_as_sf(coords = c("lon", "lat"), crs = st_crs(highlands)) %>% 
  st_join(uk_ev_map_2021, join = st_intersects, left = FALSE) group_by(region_local_authority_apr_2019_3) %>% 
Error: unexpected symbol in:
"  st_as_sf(coords = c("lon", "lat"), crs = st_crs(highlands)) %>% 
  st_join(uk_ev_map_2021, join = st_intersects, left = FALSE) group_by"
ev_no2 %>% 
  ggplot() +
  aes(x = x2021_q1, y = mean_no2) +
  geom_point() +
  geom_smooth(se = TRUE)
`geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

population <- read_csv(here("raw_data/ukpopestimatesmid2020on2021geography/MYE2 - Persons-Table 1.csv"), skip = 7) %>% 
  clean_names() %>% 
  select(code, name, all_ages) %>% 
  mutate(pop_per_100k = all_ages/100000)
New names:
* `` -> ...96
* `` -> ...97
* `` -> ...98
* `` -> ...99
* `` -> ...100
Rows: 420 Columns: 100
── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Code, Name, Geography
lgl (5): ...96, ...97, ...98, ...99, ...100

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ev_pop_100k %>% 
  ggplot() +
  aes(x = ev_per_100k, y = mean_no2) +
  geom_point() +
  geom_smooth(se = TRUE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
Warning: Removed 11 rows containing non-finite values (stat_smooth).
Warning: Removed 11 rows containing missing values (geom_point).

library(cluster)
library(factoextra)
ev_scale <- ev_pop_100k %>% 
  select(region_local_authority_apr_2019_3, x2021_q1, mean_no2) %>% 
  mutate_if(is.numeric, scale)
ev_pop_100k_scale <- ev_pop_100k %>% 
  select(region_local_authority_apr_2019_3, ev_per_100k, mean_no2) %>% 
  mutate_if(is.numeric, scale)
ev_scale %>% 
  ggplot() +
  aes(x = x2021_q1, y = mean_no2) +
  geom_point() +
  geom_smooth(method = lm)
`geom_smooth()` using formula 'y ~ x'

ev_pop_100k_scale %>% 
  ggplot() +
  aes(x = ev_per_100k, y = mean_no2) +
  geom_point() +
  geom_smooth(method = lm)
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 11 rows containing non-finite values (stat_smooth).
Warning: Removed 11 rows containing missing values (geom_point).

library(corrplot)
corrplot 0.90 loaded

car_by_fuel_gb <- read_ods(here("raw_data/car_by_fuel_by_year_ALL_UK.ods"), skip = 7) %>% 
  clean_names() %>% 
  head(58) %>% 
  mutate(across(c(petrol:zero_emission8), as.numeric)) %>% 
  filter(petrol >= 100) %>% 
  mutate(traditional_fuel = total - alternative_fuels7 - zero_emission8) %>% 
  select(c("year", "petrol", "diesel", "alternative_fuels7", "zero_emission8")) %>% 
  pivot_longer(cols = c(petrol:zero_emission8), names_to = c("fuel_type"), values_to = c("count"))
car_by_fuel_gb %>% 
  ggplot() +
  aes(x = year, y = count, colour = fuel_type) +
  geom_smooth(method = lm) +
  geom_point() 
`geom_smooth()` using formula 'y ~ x'

new_car_by_fuel_gb <- read_ods(here("raw_data/new_car_by_fuel.ods"), skip = 7) %>% 
  clean_names() %>% 
  head(21) %>% 
  mutate(across(c(petrol:zero_emission8), as.numeric)) %>% 
  filter(petrol >= 100) %>% 
  mutate(traditional_fuel = total - alternative_fuels7 - zero_emission8) %>% 
  select(c("date", "petrol", "diesel", "alternative_fuels7", "zero_emission8")) %>% 
  pivot_longer(cols = c(petrol:zero_emission8), names_to = c("fuel_type"), values_to = c("count"))

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShyZWFkT0RTKQpsaWJyYXJ5KGh0dHIpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkobGVhZmxldC5leHRyYXMpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCmBgYHtyfQojIGxvYWRpbmcgaW4gc2hhcGUgZmlsZSAKdWtfc2hhcGVfZmlsZSA8LSBzdF9yZWFkKGhlcmUoInJhd19kYXRhL0xBX3NoYXBlL0xvY2FsX0F1dGhvcml0eV9EaXN0cmljdHNfX0FwcmlsXzIwMTlfX1VLX0JGRV92Mi5zaHAiKSkgJT4lCiAgY2xlYW5fbmFtZXMoKSAlPiUgCiAgc3Rfc2ltcGxpZnkoZFRvbGVyYW5jZSA9IDEwMDApICU+JQogIHN0X3RyYW5zZm9ybSgiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiKSAlPiUgCiAgZHBseXI6OnNlbGVjdChsYWQxOWNkLCBsb25nLCBsYXQsIGdlb21ldHJ5KSAKYGBgCgpgYGB7cn0KIyBMb2FkIGluIGNsZWFuIEVsZWN0cmljIFZlaGljbGVzIGJ5IExvY2FsIEF1dGhvcml0eSBkYXRhCnVrX2V2IDwtIHJlYWRfY3N2KGhlcmUoImNsZWFuX2RhdGEvZXZfYnlfbGFfY2xlYW4uY3N2IikpCiMgSm9pbmluZyB1a19ldiArIHNoYXBlIGZpbGUgCnVrX2V2X21hcCA8LSB1a19ldiAlPiUgCiAgbGVmdF9qb2luKHVrX3NoYXBlX2ZpbGUsIGJ5ID0gYygib25zX2xhX2NvZGVfYXByXzIwMTkiID0gImxhZDE5Y2QiKSkgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgbXV0YXRlKGFjcm9zcyhjKHgyMDIxX3ExOngyMDExX3E0KSwgYXMubnVtZXJpYykpICU+JSAKICBzdF9hc19zZigpCmBgYAoKYGBge3J9CiMgU2V0IGNvbG91cnMgYW5kIGJpbnMKcGFsIDwtIGNvbG9yQmluKCJHcmVlbnMiLCBkb21haW4gPSB1a19ldl9tYXAkeDIwMjFfcTEsIGJpbnMgPSBjKDAsIDUwMCwgMTAwMCwgMjUwMCwgNTAwMCwgMTAwMDAsIDE1MDAwKSkKCiMgU2V0IGxhYmVscwp1a19ldl9tYXBfbGFiZWxzIDwtIHNwcmludGYoCiAgIjxzdHJvbmc+JXM8L3N0cm9uZz48YnIvPiVnIEVsZWN0cmljIFZlaGljbGVzIiwKICB1a19ldl9tYXAkcmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zLCB1a19ldl9tYXAkeDIwMjFfcTEpICU+JSAKICBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQpgYGAKCmBgYHtyfQojIEdlb3NwYXRpYWwgb2YgRVYgVmVoaWNsZXMgaW4gdGhlIFVLIDIwMjEgUTEKdWtfZXZfbWFwICU+JSAKICBsZWFmbGV0KCkgJT4lIAogIHNldFZpZXcobG5nID0gLTQuMjAyNiwgbGF0ID0gNTUuOCwgem9vbSA9IDQuNywgb3B0aW9ucyA9IGxpc3QoKSkgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lIAogIGFkZFBvbHlnb25zKGZpbGxDb2xvciA9IH5wYWwoeDIwMjFfcTEpLAogICAgd2VpZ2h0ID0gMC4xLAogICAgb3BhY2l0eSA9IDAuOSwgCiAgICBjb2xvciA9ICJibGFjayIsCiAgICBmaWxsT3BhY2l0eSA9IDAuOCwKICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKGNvbG9yID0gImdyZWVuIiwgd2VpZ2h0ID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpLAogICAgbGFiZWwgPSB1a19ldl9tYXBfbGFiZWxzLAogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKAogICAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiLCBwYWRkaW5nID0gIjNweCA4cHgiKSwKICAgICAgdGV4dHNpemUgPSAiMTVweCIsCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JSAKICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSB+eDIwMjFfcTEsIG9wYWNpdHkgPSAwLjcsIHRpdGxlID0gTlVMTCwKICAgICAgICAgICAgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiKQpgYGAKIyBIb3cgbWFueSBlbGVjdHJpYyB2ZWhpY2xlcyBhcmUgb24gdGhlIHJvYWQgYWNyb3NzIHRoZSBVSyBieSBMQT8KCmBgYHtyfQojIFJlYWRpbmcgaW4gYW5kIHNraXBwaW5nIGZpcnN0IDUgcm93cwp1a19ldl9wb3N0Y29kZSA8LSByZWFkX29kcyhoZXJlKCJyYXdfZGF0YS9ldl9ieV9wb3N0Y29kZS5vZHMiKSwgc2hlZXQgPSAyLCBza2lwID0gNikgJT4lIAogIHJlbmFtZSgicG9zdGNvZGUiID0gIlBvc3Rjb2RlIERpc3RyaWN0MiIpCmBgYAoKYGBge3J9CiMgbG9hZGluZyBpbiBzaGFwZSBmaWxlIAp1a19zaGFwZV9maWxlX3Bvc3Rjb2RlIDwtIHN0X3JlYWQoaGVyZSgicmF3X2RhdGEvcG9zdGNvZGVfc2hhcGUvRVhfU2FtcGxlLnNocCIpKSAlPiUKICBjbGVhbl9uYW1lcygpICU+JSAKICBzdF9zaW1wbGlmeShkVG9sZXJhbmNlID0gMTAwMCkgJT4lCiAgc3RfdHJhbnNmb3JtKCIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCIpICMlPiUgCiMgIHNlbGVjdChsYWQxOWNkLCBsb25nLCBsYXQsIGdlb21ldHJ5KSAKYGBgCgpgYGB7cn0KIyBKb2luaW5nIHVrX2V2ICsgc2hhcGUgZmlsZSAKdWtfZXZfbWFwX3Bvc3Rjb2RlIDwtIHVrX2V2X3Bvc3Rjb2RlICU+JSAKICBsZWZ0X2pvaW4odWtfc2hhcGVfZmlsZV9wb3N0Y29kZSwgYnkgPSBjKCJvbnNfbGFfY29kZV9hcHJfMjAxOSIgPSAibGFkMTljZCIpKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBtdXRhdGUoYWNyb3NzKGMoeDIwMjFfcTE6eDIwMTFfcTQpLCBhcy5udW1lcmljKSkgJT4lIAogIHN0X2FzX3NmKCkKYGBgCgoKYGBge3J9CiAgICBwYWwgPC0gY29sb3JCaW4oIkdyZWVucyIsIGRvbWFpbiA9IHVrX2V2X21hcCR4MjAyMV9xMSwgYmlucyA9IGMoMCwgNTAwLCAxMDAwLCAyNTAwLCA1MDAwLCAxMDAwMCwgMTUwMDApKQogICAgCiAgICB1a19ldl9tYXBfbGFiZWxzIDwtIHNwcmludGYoCiAgICAgICI8c3Ryb25nPiVzPC9zdHJvbmc+PGJyLz4lZyBFbGVjdHJpYyBWZWhpY2xlcyIsCiAgICAgIHVrX2V2X21hcCRyZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMsIHVrX2V2X21hcCR4MjAyMV9xMSkgJT4lIAogICAgICBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQpgYGAKCmBgYHtyfQojIEdlb3NwYXRpYWwgb2YgRVYgVmVoaWNsZXMgaW4gdGhlIFVLIDIwMjEgUTEKdWtfZXZfbWFwICU+JSAKICBsZWFmbGV0KCkgJT4lIAogIHNldFZpZXcobG5nID0gLTQuMjAyNiwgbGF0ID0gNTUuOCwgem9vbSA9IDQuNywgb3B0aW9ucyA9IGxpc3QoKSkgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lIAogIGFkZFBvbHlnb25zKGZpbGxDb2xvciA9IH5wYWwoeDIwMjFfcTEpLAogICAgd2VpZ2h0ID0gMC4xLAogICAgb3BhY2l0eSA9IDAuOSwgCiAgICBjb2xvciA9ICJibGFjayIsCiAgICBmaWxsT3BhY2l0eSA9IDAuOCwKICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKGNvbG9yID0gImdyZWVuIiwgd2VpZ2h0ID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpLAogICAgbGFiZWwgPSB1a19ldl9tYXBfbGFiZWxzLAogICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKAogICAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiLCBwYWRkaW5nID0gIjNweCA4cHgiKSwKICAgICAgdGV4dHNpemUgPSAiMTVweCIsCiAgICAgIGRpcmVjdGlvbiA9ICJhdXRvIikpICU+JSAKICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSB+eDIwMjFfcTEsIG9wYWNpdHkgPSAwLjcsIHRpdGxlID0gTlVMTCwKICAgICAgICAgICAgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiKQpgYGAKICAKYGBge3J9CiMgV3JhbmdsaW5nIHRvIGNyZWF0ZSBhbiBFViBjb3VudCBvdmVyIHRpbWUgcGxvdCAKdWtfZXZfbG9uZ2VyIDwtIHVrX2V2ICU+JQogICMgUGl2b3QgbG9uZ2VyIHRvIGdldCB5ZWFyIGFuZCBjb3VudCBjb2x1bW5zCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHgyMDIxX3ExOngyMDExX3E0KSwgbmFtZXNfdG8gPSBjKCJ5ZWFyIiksIHZhbHVlc190byA9ICJub19vZl9ldiIpICU+JSAKICAjIEZpbHRlciBzbyB3ZSBvbmx5IGhhdmUgVUsgYXMgYSB3aG9sZSBkYXRhIEFORCB3ZSBvbmx5IHdhbnQgZmluYWwgbnVtYmVycyBvZiB0aGUgeWVhciBzbyBRNCAKICBmaWx0ZXIocmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zID09ICJVbml0ZWQgS2luZ2RvbSIgJiBzdHJfZGV0ZWN0KHllYXIsICJxNCIpKSAlPiUgCiAgIyBTaW1wbGlmeSB0byBqdXN0IHNob3cgeWVhcgogIG11dGF0ZSh5ZWFyID0gY2FzZV93aGVuKHN0cl9kZXRlY3QoeWVhciwgIjIwMjEiKSB+ICIyMDIxIiwKICAgICAgICAgc3RyX2RldGVjdCh5ZWFyLCAiMjAyMCIpIH4gIjIwMjAiLAogICAgICAgICBzdHJfZGV0ZWN0KHllYXIsICIyMDE5IikgfiAiMjAxOSIsCiAgICAgICAgIHN0cl9kZXRlY3QoeWVhciwgIjIwMTgiKSB+ICIyMDE4IiwKICAgICAgICAgc3RyX2RldGVjdCh5ZWFyLCAiMjAxNyIpIH4gIjIwMTciLAogICAgICAgICBzdHJfZGV0ZWN0KHllYXIsICIyMDE2IikgfiAiMjAxNiIsCiAgICAgICAgIHN0cl9kZXRlY3QoeWVhciwgIjIwMTUiKSB+ICIyMDE1IiwKICAgICAgICAgc3RyX2RldGVjdCh5ZWFyLCAiMjAxNCIpIH4gIjIwMTQiLAogICAgICAgICBzdHJfZGV0ZWN0KHllYXIsICIyMDEzIikgfiAiMjAxMyIsCiAgICAgICAgIHN0cl9kZXRlY3QoeWVhciwgIjIwMTIiKSB+ICIyMDEyIiwKICAgICAgICAgc3RyX2RldGVjdCh5ZWFyLCAiMjAxMSIpIH4gIjIwMTEiKSwKICAgICAgICAgeWVhciA9IGFzLm51bWVyaWMoeWVhciksCiAgICAgICAgIG5vX29mX2V2ID0gYXMubnVtZXJpYyhub19vZl9ldikpCmBgYAoKCmBgYHtyfQp1a19ldl9sb25nZXIgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHllYXIsIHkgPSBub19vZl9ldikgKwogIGdlb21fY29sKGZpbGwgPSAibGF3bmdyZWVuIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDIwMTE6MjAyMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIyMDAwMCwgYnkgPSAyMDAwMCksIGxpbWl0cyA9IGMoMCwgMjIwMDAwKSkgKwogIGxhYnModGl0bGUgPSAiXG5OdW1iZXIgb2YgRWxlY3RyaWMgVmVoaWNsZXMgb3ZlciB0aW1lIGluIHRoZSBVS1xuIiwKICAgICAgIHggPSAiXG5ZZWFyXG4iLAogICAgICAgeSA9ICJcbk51bWJlciBvZiBFbGVjdHJpYyBWZWhpY2xlc1xuIikgKwogIHRoZW1lX21pbmltYWwoKSAKYGBgCgogIAoKCiMgUm93IGJpbmRpbmcgZ3JpZCBOTzIgZGF0YSAKCmBgYHtyfQpubzJfMjAxMCA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDEwLmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkKbm8yXzIwMTEgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvbm8yX2J5X2dyaWRfMjAxMS5jc3YiKSwgc2tpcCA9IDYsIAogIGNvbF9uYW1lcyA9IGMoInVrX2dyaWRfY29kZSIsICJ4IiwgInkiLCAibm8yIikpCm5vMl8yMDEyIDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL25vMl9ieV9ncmlkXzIwMTIuY3N2IiksIHNraXAgPSA2LCAKICBjb2xfbmFtZXMgPSBjKCJ1a19ncmlkX2NvZGUiLCAieCIsICJ5IiwgIm5vMiIpKQpubzJfMjAxMyA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDEzLmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkKbm8yXzIwMTQgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvbm8yX2J5X2dyaWRfMjAxNC5jc3YiKSwgc2tpcCA9IDYsIAogIGNvbF9uYW1lcyA9IGMoInVrX2dyaWRfY29kZSIsICJ4IiwgInkiLCAibm8yIikpCm5vMl8yMDE1IDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL25vMl9ieV9ncmlkXzIwMTUuY3N2IiksIHNraXAgPSA2LCAKICBjb2xfbmFtZXMgPSBjKCJ1a19ncmlkX2NvZGUiLCAieCIsICJ5IiwgIm5vMiIpKQpubzJfMjAxNiA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDE2LmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkKbm8yXzIwMTcgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvbm8yX2J5X2dyaWRfMjAxNy5jc3YiKSwgc2tpcCA9IDYsIAogIGNvbF9uYW1lcyA9IGMoInVrX2dyaWRfY29kZSIsICJ4IiwgInkiLCAibm8yIikpCm5vMl8yMDE4IDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL25vMl9ieV9ncmlkXzIwMTguY3N2IiksIHNraXAgPSA2LCAKICBjb2xfbmFtZXMgPSBjKCJ1a19ncmlkX2NvZGUiLCAieCIsICJ5IiwgIm5vMiIpKQpubzJfMjAxOSA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDE5LmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkKCiMgQ3JlYXRlIGVtcHR5IGRhdGEgZnJhbWUKbm8yX2FsbCA8LSBkYXRhX2ZyYW1lKCkKCiMgRm9yIGVhY2ggeWVhciwgYmluZCByb3dzIHRvIG9uZSBkYXRhc2V0CmZvciAoaSBpbiAyMDEwOjIwMTkpIHsKICBkZl9uYW1lIDwtIHBhc3RlMCgibm8yXyIsIGkpCiAgZGZfaW5wdXQgPC0gYXMubmFtZShkZl9uYW1lKQogIAogIGRmIDwtIGV2YWwoZGZfaW5wdXQpICU+JSAKICAgIG11dGF0ZSh5ZWFyID0gaSkKICAKbm8yX2FsbCA8LSBiaW5kX3Jvd3Mobm8yX2FsbCwgZGYpCiAgfQpgYGAKCmBgYHtyfQojIFJlbW92ZSBtaXNzaW5nIE5PMiBncmlkIHZhbHVlcwpubzJfY2xlYW4gPC0gbm8yX2FsbCAlPiUgCiAgZmlsdGVyKG5vMiAhPSAiTUlTU0lORyIpCmBgYAoKYGBge3J9CmxpYnJhcnkocHJvajQpCnByb2o0c3RyaW5nIDwtICIrcHJvaj10bWVyYyArbGF0XzA9NDkgK2xvbl8wPS0yICtrPTAuOTk5NjAxMjcxNyAreF8wPTQwMDAwMCAreV8wPS0xMDAwMDAgK2VsbHBzPWFpcnkgK2RhdHVtPU9TR0IzNiArdW5pdHM9bSArbm9fZGVmcyIKCm5vMl9jbGVhbl9yb3cgPC0gbm8yX2NsZWFuICU+JSAKICByb3dpZF90b19jb2x1bW4oKQoKIyBTb3VyY2UgZGF0YQp4eSA8LSBubzJfY2xlYW5fcm93ICU+JSAKICBzZWxlY3QoeCwgeSwgcm93aWQpCgojIFRyYW5zZm9ybWVkIGRhdGEKcGogPC0gcHJvamVjdCh4eSwgcHJvajRzdHJpbmcsIGludmVyc2U9VFJVRSkKbGF0bG9uIDwtIGRhdGEuZnJhbWUoeHksIGxhdD1waiR5LCBsb249cGokeCkKZmluYWwgPC0gIG1lcmdlKG5vMl9jbGVhbl9yb3csIGxhdGxvbiwgYnkueCA9ICJyb3dpZCIsIGJ5LnkgPSAicm93aWQiKSAlPiUKICBmaWx0ZXIoeWVhciA9PSAyMDE5KSAlPiUgCiAgc2VsZWN0KGxhdCwgbG9uLCBubzIpIApgYGAKCmBgYHtyfQpmaW5hbCA8LSBmaW5hbCAlPiUgCiAgbXV0YXRlKG5vMiA9IGFzLm51bWVyaWMobm8yKSkgCmBgYAoKYGBge3J9CmJpbnMgPC0gYygxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5LCAxMCkKcGFsIDwtIGNvbG9yQmluKCJTcGVjdHJhbCIsIGRvbWFpbiA9IGZpbmFsJG5vMiwgYmlucyA9IGJpbnMsIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IiwgcmV2ZXJzZSA9IFRSVUUpCgpsZWFmbGV0KCkgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQi5Qb3NpdHJvbiIsIG9wdGlvbnMgPSBwcm92aWRlclRpbGVPcHRpb25zKG5vV3JhcCA9IFRSVUUpKSAlPiUKICBzZXRWaWV3KGxuZyA9IC00LjIwMjYsIGxhdCA9IDU1LjgsIHpvb20gPSA0LjcsIG9wdGlvbnMgPSBsaXN0KCkpICU+JQogIGFkZEhlYXRtYXAoZGF0YSA9IGZpbmFsLAogICAgICAgICAgICAgbG5nID0gfmxvbiwKICAgICAgICAgICAgIGxhdCA9IH5sYXQsCiAgICAgICAgICAgICBpbnRlbnNpdHkgPSB+bm8yLAogICAgICAgICAgICAgbWluT3BhY2l0eSA9IDAuMSwKICAgICAgICAgICAgIG1heCA9IDQ1LAogICAgICAgICAgICAgcmFkaXVzID0gMSwKICAgICAgICAgICAgIGJsdXIgPSAxKSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gZmluYWwkbm8yLAogICAgICAgICAgICAgICAgdGl0bGU9IkF2ZXJhZ2UgTk8yIENvbmMiKQpgYGAKCmBgYHtyfQpubzJfYW5udWFsX21lYW4gPC0gcmVhZF9vZHMoaGVyZSgicmF3X2RhdGEvTk8yX3RhYmxlcy5vZHMiKSwgc2hlZXQgPSAzLCBza2lwID0gMikgJT4lIAogIGNsZWFuX25hbWVzKCkKYGBgCgpgYGB7cn0Kbm8yX2FubnVhbF9tZWFuX2FsbCA8LSBubzJfYW5udWFsX21lYW4gJT4lIAogIGZpbHRlcihzaXRlID09ICJBbGwgc2l0ZXMiKSAlPiUgCiAgbXV0YXRlKHllYXIgPSBhcy5udW1lcmljKHllYXIpKQpgYGAKCmBgYHtyfQpubzJfYW5udWFsX21lYW5fYWxsICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSB5ZWFyLCB5ID0gYW5udWFsX21lYW5fbm8yY29uY2VudHJhdGlvbl9tZ19tMykgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNzAsIDEwKSwgbGltaXRzID0gYygwLCA3MCkpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpICsKICBsYWJzKHggPSAiXG5ZZWFyXG4iLCAKICAgICAgIHkgPSAiXG5Bbm51YWwgTWVhbiBOTzIgQ29uYyBtZyBtM1xuIiwKICAgICAgIHRpdGxlID0gIlxuTk8yIG92ZXIgdGltZSBpbiB0aGUgVUtcbiIpIApgYGAKCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZmFibGUpCmxpYnJhcnkodHNpYmJsZSkKbGlicmFyeSh0c2liYmxlZGF0YSkKbGlicmFyeShnZ2ZvcnRpZnkpCmBgYAoKYGBge3J9CmZvcmVjYXN0X25vMiA8LSBubzJfYW5udWFsX21lYW5fYWxsICU+JSAKICBkcGx5cjo6c2VsZWN0KHllYXIsIGFubnVhbF9tZWFuX25vMmNvbmNlbnRyYXRpb25fbWdfbTMpICU+JSAKICB0c2liYmxlKGluZGV4ID0geWVhcikKYGBgCgpgYGB7cn0KYXV0b3Bsb3QoZm9yZWNhc3Rfbm8yKQpgYGAKCmBgYHtyfQpmaXQgPC0gZm9yZWNhc3Rfbm8yICU+JQogIG1vZGVsKAogICAgYXJpbWEgPSBBUklNQShhbm51YWxfbWVhbl9ubzJjb25jZW50cmF0aW9uX21nX20zKQogICkKZml0CmBgYAoKYGBge3J9CmZvcmVjYXN0XzEgPC0gZml0ICU+JQogIGZhYmxldG9vbHM6OmZvcmVjYXN0KGggPSAiMTUgeWVhcnMiKQpmb3JlY2FzdF8xCmBgYAoKYGBge3J9CmZvcmVjYXN0XzEgJT4lCiAgYXV0b3Bsb3QoZm9yZWNhc3Rfbm8yLCBsZXZlbCA9IE5VTEwpICsKICBnZ3RpdGxlKCJGb3JlY2FzdHMgZm9yIE5PMiBDb25jIG92ZXIgdGltZSIpICsKICB4bGFiKCJZZWFyIikgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiRm9yZWNhc3QiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdCA9IGMoMCwgNjUpKQpgYGAKCmBgYHtyfQojIE5vdyBzZXQgb3VyIHRyYWluaW5nIGRhdGEgZnJvbSAxOTkyIHRvIDIwMDYKdHJhaW4gPC0gZm9yZWNhc3Rfbm8yICU+JQogIGZpbHRlcih5ZWFyIDw9IDIwMTcpCgojIHJ1biB0aGUgbW9kZWwgb24gdGhlIHRyYWluaW5nIHNldCAKZml0X3RyYWluIDwtIHRyYWluICU+JQogIG1vZGVsKAogICAgYXJpbWEgPSBBUklNQShhbm51YWxfbWVhbl9ubzJjb25jZW50cmF0aW9uX21nX20zKQogICkKYGBgCgpgYGB7cn0KIyBmb3JlY2FzdCBmcm9tIHRoZSB0cmFpbmluZyBzZXQKZm9yZWNhc3RfdGVzdCA8LSBmaXRfdHJhaW4gJT4lIAogIGZhYmxldG9vbHM6OmZvcmVjYXN0KGggPSAiNCB5ZWFycyIpCgojIFBsb3QgZm9yZWNhc3RzIGFnYWluc3QgYWN0dWFsIHZhbHVlcwpmb3JlY2FzdF90ZXN0ICU+JQogIGF1dG9wbG90KHRyYWluLCBsZXZlbCA9IE5VTEwpICsKICAgIGF1dG9sYXllcihmaWx0ZXIoZm9yZWNhc3Rfbm8yLCB5ZWFyID49IDIwMTcpLCBjb2xvciA9ICJibGFjayIpICsKICAgIGdndGl0bGUoIkZvcmVjYXN0cyBmb3IgTk8yIENvbmMgb3ZlciB0aW1lIikgKwogICAgeGxhYigiWWVhciIpICsgeWxhYigiTWVnYWxpdHJlcyIpICsKICAgIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKHRpdGxlPSJGb3JlY2FzdCIpKQpgYGAKCmBgYHtyfQojIEJpbmRpbmcgMjAxNCBhbmQgMjAxOQpubzJfMjAxNCA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDE0LmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkgJT4lIAogIGFkZF9jb2x1bW4oeWVhciA9ICIyMDE0IikKbm8yXzIwMTkgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvbm8yX2J5X2dyaWRfMjAxOS5jc3YiKSwgc2tpcCA9IDYsIAogIGNvbF9uYW1lcyA9IGMoInVrX2dyaWRfY29kZSIsICJ4IiwgInkiLCAibm8yIikpICU+JSAKICBhZGRfY29sdW1uKHllYXIgPSAiMjAxOSIpCgpubzJfZGlmZmVyZW5jZSA8LSBiaW5kX3Jvd3Mobm8yXzIwMTQsIG5vMl8yMDE5KQpgYGAKCmBgYHtyfQojIERpZmYgaW4gTk8yIGJldHdlZW4gMjAxNCAmIDIwMTkKbm8yX2RpZmZlcmVuY2UgPC0gbm8yX2RpZmZlcmVuY2UgJT4lIAogIGZpbHRlcihubzIgIT0gIk1JU1NJTkciKSAlPiUgCiAgbXV0YXRlKG5vMiA9IGFzLm51bWVyaWMobm8yKSwKICAgICAgICAgeWVhciA9IGFzLm51bWVyaWMoeWVhcikpICU+JSAKICBncm91cF9ieSh4LCB5KSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJ5ZWFyIiwgdmFsdWVzX2Zyb20gPSAibm8yIikgJT4lIAogIHJlbmFtZSgieDIwMTQiID0gIjIwMTQiLAogICAgICAgICAieDIwMTkiID0gIjIwMTkiKSAlPiUgCiAgbXV0YXRlKG5vMl9kaWZmXzIwMTRfMjAxOSA9IHgyMDE0IC0geDIwMTkpICAlPiUgCiNSZW1vdmUgdGhpcyBzZXBhcmF0aW9uIHdoZW4gcHV0IGluIGNsZWFuaW5nIHNjcmlwdAogIHVuZ3JvdXAoKSAlPiUgCiNSZW1vdmUgdGhpcyBzZXBhcmF0aW9uIHdoZW4gcHV0IGluIGNsZWFuaW5nIHNjcmlwdAogIGRyb3BfbmEoKSAlPiUgCiNSZW1vdmUgdGhpcyBzZXBhcmF0aW9uIHdoZW4gcHV0IGluIGNsZWFuaW5nIHNjcmlwdAojIENoYW5naW5nIGFsbCBuZWdhdGl2ZSBudW1iZXJzIHRvIHplcm8gYXMgdGhlc2UgYXJlbid0IG9mIGludGVyZXN0IHRvIHVzCiAgbXV0YXRlKG5vMl9kaWZmXzIwMTRfMjAxOSA9IGlmX2Vsc2Uobm8yX2RpZmZfMjAxNF8yMDE5IDwgMCwgMCwgbm8yX2RpZmZfMjAxNF8yMDE5KSkKYGBgCgpgYGB7cn0KIyBDb252ZXJ0aW5nIE5PMiBkaWZmIGZyb20geCB5IHRvIGxhdCBsb25nCmxpYnJhcnkocHJvajQpCnByb2o0c3RyaW5nIDwtICIrcHJvaj10bWVyYyArbGF0XzA9NDkgK2xvbl8wPS0yICtrPTAuOTk5NjAxMjcxNyAreF8wPTQwMDAwMCAreV8wPS0xMDAwMDAgK2VsbHBzPWFpcnkgK2RhdHVtPU9TR0IzNiArdW5pdHM9bSArbm9fZGVmcyIKCm5vMl9kaWZmX3JvdyA8LSBubzJfZGlmZmVyZW5jZSAlPiUgCiAgcm93aWRfdG9fY29sdW1uKCkKCiMgU291cmNlIGRhdGEKeHkgPC0gbm8yX2RpZmZfcm93ICU+JSAKICBkcGx5cjo6c2VsZWN0KHgsIHksIHJvd2lkKQoKIyBUcmFuc2Zvcm1lZCBkYXRhCnBqIDwtIHByb2plY3QoeHksIHByb2o0c3RyaW5nLCBpbnZlcnNlPVRSVUUpCmxhdGxvbiA8LSBkYXRhLmZyYW1lKHh5LCBsYXQ9cGokeSwgbG9uPXBqJHgpCm5vMl9kaWZmX2ZpbmFsIDwtICBtZXJnZShubzJfZGlmZl9yb3csIGxhdGxvbiwgYnkueCA9ICJyb3dpZCIsIGJ5LnkgPSAicm93aWQiKSAlPiUKICBkcGx5cjo6c2VsZWN0KGxhdCwgbG9uLCBubzJfZGlmZl8yMDE0XzIwMTkpIApgYGAKCmBgYHtyfQojIEdlb3NwYXRpYWwgb2YgTm8yIGRpZmYgMjAxNCB0byAyMDE5CmJpbnMgPC0gYygwLCA1LCAxMCwgMTUsIDIwLCAyNSwgMzApCnBhbCA8LSBjb2xvckJpbigiU3BlY3RyYWwiLCBkb21haW4gPSBubzJfZGlmZl9maW5hbCRubzJfZGlmZl8yMDE0XzIwMTksIGJpbnMgPSBiaW5zLCBuYS5jb2xvciA9ICJ0cmFuc3BhcmVudCIsIHJldmVyc2UgPSBUUlVFKQoKbGVhZmxldCgpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iLCBvcHRpb25zID0gcHJvdmlkZXJUaWxlT3B0aW9ucyhub1dyYXAgPSBUUlVFKSkgJT4lCiAgc2V0VmlldyhsbmcgPSAtNC4yMDI2LCBsYXQgPSA1NS44LCB6b29tID0gNC43LCBvcHRpb25zID0gbGlzdCgpKSAlPiUKICBhZGRIZWF0bWFwKGRhdGEgPSBubzJfZGlmZl9maW5hbCwKICAgICAgICAgICAgIGxuZyA9IH5sb24sCiAgICAgICAgICAgICBsYXQgPSB+bGF0LAogICAgICAgICAgICAgaW50ZW5zaXR5ID0gfm5vMl9kaWZmXzIwMTRfMjAxOSwKICAgICAgICAgICAgIG1pbk9wYWNpdHkgPSAwLjEsCiAgICAgICAgICAgICBtYXggPSAzMCwKICAgICAgICAgICAgIHJhZGl1cyA9IDEsCiAgICAgICAgICAgICBibHVyID0gMikgJT4lIAogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IG5vMl9kaWZmX2ZpbmFsJG5vMl9kaWZmXzIwMTRfMjAxOSwKICAgICAgICAgICAgICAgIHRpdGxlPSJBbm51YWwgTWVhbiBOTzIgQ2hhbmdlIGJldHdlZW4gMjAxNCBhbmQgMjAxOSIpCmBgYAoKCmBgYHtyfQpubzJfZGlmZmVyZW5jZSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gbm8yX2RpZmZfMjAxNF8yMDE5KSkKYGBgCgpgYGB7cn0KZXZfY2hhcmdpbmcgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvZWxlY3RyaWMtdmVoaWNsZS1jaGFyZ2luZy1kZXZpY2Utc3RhdGlzdGljcy1qdWx5LTIwMjEvRVZDRF8wMi1UYWJsZSAxLmNzdiIpLCBza2lwID0gNikgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lIAogIGRwbHlyOjpzZWxlY3QoeWVhciwgbW9udGgsIHRvdGFsX2RldmljZXMsIHJhcGlkX2RldmljZXMpICU+JSAKICBmaWx0ZXIocmFwaWRfZGV2aWNlcyAhPSAiTkEiKSAlPiUgCiAgbXV0YXRlKHRvdGFsX2RldmljZXMgPSBhcy5udW1lcmljKHRvdGFsX2RldmljZXMpLAogICAgICAgICBvdGhlcl9kZXZpY2VzID0gdG90YWxfZGV2aWNlcyAtIHJhcGlkX2RldmljZXMpICU+JSAKICBzZWxlY3QoLXRvdGFsX2RldmljZXMpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMob3RoZXJfZGV2aWNlcywgcmFwaWRfZGV2aWNlcyksIG5hbWVzX3RvID0gImNoYXJnZXIiLCB2YWx1ZXNfdG8gPSAibnVtYmVyX29mX2NoYXJnZXJzIikgJT4lIAogIGZpbHRlcihtb250aCA9PSAiT2N0b2JlciIgfCBtb250aCA9PSAiSnVseSIgJiB5ZWFyID09ICIyMDIxIikgJT4lIAogIG11dGF0ZShjaGFyZ2VyID0gZmFjdG9yKGNoYXJnZXIsIGxldmVscyA9IGMoInJhcGlkX2RldmljZXMiLCAib3RoZXJfZGV2aWNlcyIpKSkKYGBgCgpgYGB7cn0KZXZfY2hhcmdpbmcgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHllYXIsIHkgPSBudW1iZXJfb2ZfY2hhcmdlcnMsIGZpbGwgPSBjaGFyZ2VyKSArCiAgZ2VvbV9jb2woKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAzMDAwMCwgMjUwMCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKGxhYmVscyA9IGMoIlJhcGlkIENoYXJnZXIiLCAiU3RhbmRhcmQgQ2hhcmdlciIpLCB2YWx1ZXMgPSBjKCIjZTQxYTFjIiwgIiM0ZGFmNGEiKSkgKwogIGxhYnModGl0bGUgPSAiXG5OdW1iZXIgb2YgRWxlY3RyaWMgVmVoaWNsZSBDaGFyZ2VycyBHcm93dGggaW4gdGhlIFVLXG4iLAogICAgICAgeCA9ICJcblllYXJcbiIsCiAgICAgICB5ID0gIlxuTnVtYmVyIG9mIENoYXJnZXJzXG4iLAogICAgICAgZmlsbCA9ICJDaGFyZ2VyIFR5cGUiKQpgYGAKCmBgYHtyfQpldl9jaGFyZ2luZ19yYXBpZCA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9lbGVjdHJpYy12ZWhpY2xlLWNoYXJnaW5nLWRldmljZS1zdGF0aXN0aWNzLWp1bHktMjAyMS9FVkNEXzAxYi1UYWJsZSAxLmNzdiIpLCBza2lwID0gNikgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lIAogIHNlbGVjdChsYV9yZWdpb25fY29kZSwgbG9jYWxfYXV0aG9yaXR5X3JlZ2lvbl9uYW1lLCB4NikgJT4lIAogIHJlbmFtZSgiY291bnRfcmFwaWQiID0geDYpCmV2X2NoYXJnaW5nX3RvdGFsIDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL2VsZWN0cmljLXZlaGljbGUtY2hhcmdpbmctZGV2aWNlLXN0YXRpc3RpY3MtanVseS0yMDIxL0VWQ0RfMDFhLVRhYmxlIDEuY3N2IiksIHNraXAgPSA2KSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUgCiAgc2VsZWN0KGxhX3JlZ2lvbl9jb2RlLCBsb2NhbF9hdXRob3JpdHlfcmVnaW9uX25hbWUsIHg2KSAlPiUgCiAgcmVuYW1lKCJjb3VudF90b3RhbCIgPSB4NikKCmV2X2NoYXJnaW5nX2dlbyA8LSBpbm5lcl9qb2luKGV2X2NoYXJnaW5nX3JhcGlkLCBldl9jaGFyZ2luZ190b3RhbCwgYnkgPSAibGFfcmVnaW9uX2NvZGUiKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBzZWxlY3QobGFfcmVnaW9uX2NvZGUsIGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54LCBjb3VudF9yYXBpZCwgY291bnRfdG90YWwpICU+JSAKICBmaWx0ZXIoc3RyX2RldGVjdChsb2NhbF9hdXRob3JpdHlfcmVnaW9uX25hbWUueCwgIlthLXpdW2Etel0iKSwgCiAgICAgICAgIGNvdW50X3JhcGlkICE9ICItIikgJT4lIAogIG11dGF0ZShsb2NhbF9hdXRob3JpdHlfcmVnaW9uX25hbWUueCA9IHN0cl9yZW1vdmVfYWxsKGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54LCAiWyhdKE1ldCBDb3VudHkpWyldIiksCiAgICAgICAgIGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54ID0gc3RyX3JlbW92ZV9hbGwobG9jYWxfYXV0aG9yaXR5X3JlZ2lvbl9uYW1lLngsICJbKF1hYm9saXNoZWQgXFx3KyBcXGQrWyldIikpCmBgYAoKYGBge3J9CiMgSm9pbmluZyBldl9jaGFyZ2luZ19nZW8gKyBzaGFwZSBmaWxlIApldl9jaGFyZ2luZ19tYXAgPC0gZXZfY2hhcmdpbmdfZ2VvICU+JSAKICBpbm5lcl9qb2luKHVrX3NoYXBlX2ZpbGUsIGJ5ID0gYygibGFfcmVnaW9uX2NvZGUiID0gImxhZDE5Y2QiKSkgJT4lIAogIG11dGF0ZShhY3Jvc3MoYyhjb3VudF9yYXBpZDpjb3VudF90b3RhbCksIGFzLm51bWVyaWMpKSAlPiUgCiAgc3RfYXNfc2YoKQpgYGAKCmBgYHtyfQojIFNldCBjb2xvdXJzIGFuZCBiaW5zCnBhbCA8LSBjb2xvckJpbigiUmVkcyIsIGRvbWFpbiA9IGV2X2NoYXJnaW5nX21hcCRjb3VudF90b3RhbCwgYmlucyA9IDEwKQoKIyBTZXQgbGFiZWxzCmV2X2NoYXJnaW5nX21hcF9sYWJlbHMgPC0gc3ByaW50ZigKICAiPHN0cm9uZz4lczwvc3Ryb25nPjxici8+JWcgQ2hhcmdlcnMgcGVyIDEwMGsgUG9wdWxhdGlvbiIsCiAgZXZfY2hhcmdpbmdfbWFwJGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54LCBldl9jaGFyZ2luZ19tYXAkY291bnRfdG90YWwsIGV2X2NoYXJnaW5nX21hcCRjb3VudF9yYXBpZCkgJT4lIAogIGxhcHBseShodG1sdG9vbHM6OkhUTUwpCmBgYAoKYGBge3J9CiMgR2Vvc3BhdGlhbCBvZiBFViBDaGFyZ2VycyBQZXIgMTAwayBwZW9wbGUgaW4gdGhlIFVLIEFwcmlsIDIxCmV2X2NoYXJnaW5nX21hcCAlPiUgCiAgbGVhZmxldCgpICU+JSAKICBzZXRWaWV3KGxuZyA9IC00LjIwMjYsIGxhdCA9IDU1LjgsIHpvb20gPSA0LjcsIG9wdGlvbnMgPSBsaXN0KCkpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JSAKICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSB+cGFsKGNvdW50X3RvdGFsKSwKICAgIHdlaWdodCA9IDAuMSwKICAgIG9wYWNpdHkgPSAwLjksIAogICAgY29sb3IgPSAiYmxhY2siLAogICAgZmlsbE9wYWNpdHkgPSAwLjgsCiAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJncmVlbiIsIHdlaWdodCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwKICAgIGxhYmVsID0gZXZfY2hhcmdpbmdfbWFwX2xhYmVscywKICAgIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucygKICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksCiAgICAgIHRleHRzaXplID0gIjE1cHgiLAogICAgICBkaXJlY3Rpb24gPSAiYXV0byIpKSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gfmNvdW50X3RvdGFsLCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IikKYGBgCgoKYGBge3J9CiMgU2V0IGNvbG91cnMgYW5kIGJpbnMKcGFsIDwtIGNvbG9yQmluKCJSZWRzIiwgZG9tYWluID0gZXZfY2hhcmdpbmdfbWFwJGNvdW50X3JhcGlkLCBiaW5zID0gMTApCgojIFNldCBsYWJlbHMKZXZfY2hhcmdpbmdfbWFwX2xhYmVscyA8LSBzcHJpbnRmKAogICI8c3Ryb25nPiVzPC9zdHJvbmc+PGJyLz4lZyBDaGFyZ2VycyIsCiAgZXZfY2hhcmdpbmdfbWFwJGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54LCBldl9jaGFyZ2luZ19tYXAkY291bnRfcmFwaWQsIGV2X2NoYXJnaW5nX21hcCRjb3VudF90b3RhbCkgJT4lIAogIGxhcHBseShodG1sdG9vbHM6OkhUTUwpCmBgYAoKYGBge3J9CiMgR2Vvc3BhdGlhbCBvZiBFViBSYXBpZCBDaGFyZ2VycyBwZXIgMTAwayBwZW9wbGUgaW4gdGhlIFVLIEFwcmlsIDIxCmV2X2NoYXJnaW5nX21hcCAlPiUgCiAgbGVhZmxldCgpICU+JSAKICBzZXRWaWV3KGxuZyA9IC00LjIwMjYsIGxhdCA9IDU1LjgsIHpvb20gPSA0LjcsIG9wdGlvbnMgPSBsaXN0KCkpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JSAKICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSB+cGFsKGNvdW50X3JhcGlkKSwKICAgIHdlaWdodCA9IDAuMSwKICAgIG9wYWNpdHkgPSAwLjksIAogICAgY29sb3IgPSAiYmxhY2siLAogICAgZmlsbE9wYWNpdHkgPSAwLjgsCiAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJncmVlbiIsIHdlaWdodCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwKICAgIGxhYmVsID0gZXZfY2hhcmdpbmdfbWFwX2xhYmVscywKICAgIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucygKICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksCiAgICAgIHRleHRzaXplID0gIjE1cHgiLAogICAgICBkaXJlY3Rpb24gPSAiYXV0byIpKSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gfmNvdW50X3JhcGlkLCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IikKYGBgCgpgYGB7cn0KdWtfZXZfbWFwXzIwMjEgPC0gdWtfZXZfbWFwICU+JSAKICBzZWxlY3Qob25zX2xhX2NvZGVfYXByXzIwMTksIHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMywgeDIwMjFfcTEsIGdlb21ldHJ5KQoKIyBmaWx0ZXIgZm9yIGRlc2lyZWQgcG9seWdvbgpoaWdobGFuZHMgPC0gdWtfZXZfbWFwXzIwMjEgJT4lIAogIGZpbHRlcihyZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMgPT0gIkhpZ2hsYW5kIikgCgojIHN0X2pvaW4gc2VlbXMgbGVzcyBkaXJ0eQpldl9ubzIgPC0gZmluYWwgJT4lIAogIHN0X2FzX3NmKGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzID0gc3RfY3JzKGhpZ2hsYW5kcykpICU+JSAKICBzdF9qb2luKHVrX2V2X21hcF8yMDIxLCBqb2luID0gc3RfaW50ZXJzZWN0cywgbGVmdCA9IEZBTFNFKSAlPiUgCiAgZ3JvdXBfYnkocmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zKSAlPiUgCiAgbXV0YXRlKG1lYW5fbm8yID0gc3VtKG5vMikpCmBgYAoKYGBge3J9CmV2X25vMiAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0geDIwMjFfcTEsIHkgPSBtZWFuX25vMikgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBUUlVFKQpgYGAKCmBgYHtyfQpwb3B1bGF0aW9uIDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL3VrcG9wZXN0aW1hdGVzbWlkMjAyMG9uMjAyMWdlb2dyYXBoeS9NWUUyIC0gUGVyc29ucy1UYWJsZSAxLmNzdiIpLCBza2lwID0gNykgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lIAogIHNlbGVjdChjb2RlLCBuYW1lLCBhbGxfYWdlcykgJT4lIAogIG11dGF0ZShwb3BfcGVyXzEwMGsgPSBhbGxfYWdlcy8xMDAwMDApCmBgYAoKYGBge3J9CmV2X25vMl90YmwgPC0gdGliYmxlKGV2X25vMikgJT4lIAogIHNlbGVjdCgtYyhubzIsIGdlb21ldHJ5KSkgJT4lIAogIHVuaXF1ZSgpCmBgYAoKCmBgYHtyfQpldl9wb3BfMTAwayA8LSBldl9ubzJfdGJsICU+JSAKICBsZWZ0X2pvaW4ocG9wdWxhdGlvbiwgYnkgPSBjKCJvbnNfbGFfY29kZV9hcHJfMjAxOSIgPSAiY29kZSIpKSAlPiUgCiAgbXV0YXRlKGV2X3Blcl8xMDBrID0geDIwMjFfcTEvcG9wX3Blcl8xMDBrKSAKYGBgCgpgYGB7cn0KZXZfcG9wXzEwMGsgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IGV2X3Blcl8xMDBrLCB5ID0gbWVhbl9ubzIpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gVFJVRSkKYGBgCgpgYGB7cn0KbGlicmFyeShjbHVzdGVyKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmBgYAoKYGBge3J9CmV2X3NjYWxlIDwtIGV2X3BvcF8xMDBrICU+JSAKICBzZWxlY3QocmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zLCB4MjAyMV9xMSwgbWVhbl9ubzIpICU+JSAKICBtdXRhdGVfaWYoaXMubnVtZXJpYywgc2NhbGUpCmBgYAoKYGBge3J9CmV2X3BvcF8xMDBrX3NjYWxlIDwtIGV2X3BvcF8xMDBrICU+JSAKICBzZWxlY3QocmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zLCBldl9wZXJfMTAwaywgbWVhbl9ubzIpICU+JSAKICBtdXRhdGVfaWYoaXMubnVtZXJpYywgc2NhbGUpCmBgYAoKYGBge3J9CmV2X3NjYWxlICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSB4MjAyMV9xMSwgeSA9IG1lYW5fbm8yKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSkKYGBgCgpgYGB7cn0KZXZfcG9wXzEwMGtfc2NhbGUgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IGV2X3Blcl8xMDBrLCB5ID0gbWVhbl9ubzIpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGNvcnJwbG90KQpgYGAKYGBge3J9CmV2X3BvcF8xMDBrX3NjYWxlICU+JSAKICBhc190aWJibGUoKSAlPiUKICBwaXZvdF9sb25nZXIoLXJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMywKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidHlwZSIsIAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBncm91cF9ieSh0eXBlKSAlPiUKICBzdW1tYXJpc2UobWVhbiA9IHJvdW5kKG1lYW4odmFsdWUpKSwgCiAgICAgICAgICAgIHNkID0gc2QodmFsdWUpKQpgYGAKYGBge3J9CmV2X3BvcF8xMDBrX3NjYWxlX251bWVyaWMgPC0gZXZfcG9wXzEwMGtfc2NhbGUgJT4lIAogIHNlbGVjdCgtcmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zKQpgYGAKCgpgYGB7cn0KY29ycnBsb3QoY29yKGV2X3BvcF8xMDBrX3NjYWxlX251bWVyaWMpLCBtZXRob2QgPSAibnVtYmVyIiwgdHlwZSA9ICJsb3dlciIpCmBgYAoKYGBge3J9CmNhcl9ieV9mdWVsX2diIDwtIHJlYWRfb2RzKGhlcmUoInJhd19kYXRhL2Nhcl9ieV9mdWVsX2J5X3llYXJfQUxMX1VLLm9kcyIpLCBza2lwID0gNykgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lIAogIGhlYWQoNTgpICU+JSAKICBtdXRhdGUoYWNyb3NzKGMocGV0cm9sOnplcm9fZW1pc3Npb244KSwgYXMubnVtZXJpYykpICU+JSAKICBmaWx0ZXIocGV0cm9sID49IDEwMCkgJT4lIAogIG11dGF0ZSh0cmFkaXRpb25hbF9mdWVsID0gdG90YWwgLSBhbHRlcm5hdGl2ZV9mdWVsczcgLSB6ZXJvX2VtaXNzaW9uOCkgJT4lIAogIHNlbGVjdChjKCJ5ZWFyIiwgInBldHJvbCIsICJkaWVzZWwiLCAiYWx0ZXJuYXRpdmVfZnVlbHM3IiwgInplcm9fZW1pc3Npb244IikpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMocGV0cm9sOnplcm9fZW1pc3Npb244KSwgbmFtZXNfdG8gPSBjKCJmdWVsX3R5cGUiKSwgdmFsdWVzX3RvID0gYygiY291bnQiKSkKYGBgCgpgYGB7cn0KY2FyX2J5X2Z1ZWxfZ2IgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHllYXIsIHkgPSBjb3VudCwgY29sb3VyID0gZnVlbF90eXBlKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0pICsKICBnZW9tX3BvaW50KCkgCmBgYAoKYGBge3J9Cm5ld19jYXJfYnlfZnVlbF9nYiA8LSByZWFkX29kcyhoZXJlKCJyYXdfZGF0YS9uZXdfY2FyX2J5X2Z1ZWwub2RzIiksIHNraXAgPSA3KSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUgCiAgaGVhZCgyMSkgJT4lIAogIG11dGF0ZShhY3Jvc3MoYyhwZXRyb2w6emVyb19lbWlzc2lvbjgpLCBhcy5udW1lcmljKSkgJT4lIAogIGZpbHRlcihwZXRyb2wgPj0gMTAwKSAlPiUgCiAgbXV0YXRlKHRyYWRpdGlvbmFsX2Z1ZWwgPSB0b3RhbCAtIGFsdGVybmF0aXZlX2Z1ZWxzNyAtIHplcm9fZW1pc3Npb244KSAlPiUgCiAgc2VsZWN0KGMoImRhdGUiLCAicGV0cm9sIiwgImRpZXNlbCIsICJhbHRlcm5hdGl2ZV9mdWVsczciLCAiemVyb19lbWlzc2lvbjgiKSkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gYyhwZXRyb2w6emVyb19lbWlzc2lvbjgpLCBuYW1lc190byA9IGMoImZ1ZWxfdHlwZSIpLCB2YWx1ZXNfdG8gPSBjKCJjb3VudCIpKQpgYGAKCmBgYHtyfQpuZXdfY2FyX2J5X2Z1ZWxfZ2IgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IGRhdGUsIHkgPSBjb3VudCwgY29sb3VyID0gZnVlbF90eXBlKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGZ1ZWxfdHlwZSkpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiTmV3IENhciBSZWdpc3RyYXRpb25zIGJ5IEZ1ZWwgVHlwZSIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgeSA9ICJOdW1iZXIgb2YgQ2FycyAoJzAwMHMpIiwKICAgICAgIGNvbG91ciA9ICJGdWVsIFR5cGUiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbChsYWJlbHMgPSBjKCJBbHRlcm5hdGl2ZSBGdWVscyIsICJEaWVzZWwiLCAiUGV0cm9sIiwgIlplcm8gRW1pc3Npb24iKSwgdmFsdWVzID0gYygiI2FiZGRhNCIsICIjZDcxOTFjIiwgIiNmZGFlNjEiLCAiIzJiODNiYSIpKSAKYGBgCgo=